//
// Created by Administrator on 2024/10/25.
//

#include "Downloader.h"
#include "UuidGenerate.h"
#include <iostream>
#include <stdexcept>
#include <fstream>
#include <curl/curl.h>
#include <format>
#include <future>


size_t Downloader::writeCallback(void* ptr, size_t size, size_t nmemb, std::ofstream* stream)
{
    stream->write(static_cast<char*>(ptr), size * nmemb);
    return size * nmemb;
}



std::string Downloader::curlTask(const std::string &url, const std::string &outputFile) {
    CURL *curl = curl_easy_init();
    if (!curl) {
        throw std::runtime_error("Failed to initialize curl: file:" + std::string(url));
    }

    std::ofstream output(outputFile, std::ios::binary);
    if (!output.is_open()) {
        throw std::runtime_error("Failed to open output file for writing." + std::string(url));
    }

    struct curl_slist* header_list = nullptr;
    auto userAgent = "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko";
    header_list = curl_slist_append(header_list,userAgent );
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);
    curl_easy_setopt(curl, CURLOPT_HEADER, 0);
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, nullptr);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &output);
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 6);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60);

    CURLcode res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        throw std::runtime_error("curl_easy_perform() failed file:" + url + std::string(curl_easy_strerror(res)));
    }

    curl_easy_cleanup(curl);
    output.close();
    return outputFile;
}

Promise<std::string> Downloader::Gather(std::vector<std::string> urls, const std::string& file_prefix) {
    auto pp = co_await Awaiter<Promise<std::string>::promise_type>{};
    for (const auto& url : urls) {
        std::string uuid = UuidGenerate::uuid37();
        std::string filePath = std::format("{}/{}.dcm", file_prefix, uuid);
        std::string downloadedFile = curlTask(url, filePath);
        pp->value_ = downloadedFile;
        co_await std::suspend_always{};
    }
}

std::vector<std::string> Downloader::Executor(std::vector<std::string>& urls, const std::string& file_prefix) {
    std::vector<std::string> tmp_files;
    std::coroutine_handle<Promise<std::string>::promise_type> handler = Downloader::Gather(urls,file_prefix);
    Promise<std::string>::promise_type &promise = handler.promise();
    for (auto url :urls) {
        tmp_files.emplace_back(promise.value_);
        handler();
    }

    return  tmp_files;
}







